package delayed.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import delayed.boundedbuffer.BoundedBuffer;
import delayed.network.Network;

public class DelayedDatagramSocket extends DatagramSocket {

	private BoundedBuffer<DatagramPacket> buffer = new BoundedBuffer<DatagramPacket>(
			-1);
	private Thread t = new Thread(new Sender(buffer));
	private boolean stop = false;
	private Network bandwidthSource; // defines the bandwidth

	public DelayedDatagramSocket(Network n) throws SocketException {
		super();
		setup(n);
	}

	public DelayedDatagramSocket(int arg0, Network n) throws SocketException {
		super(arg0);
		setup(n);
	}

	private void setup(Network n) {
		this.bandwidthSource = n;
		t.start();
	}

	public synchronized void send(DatagramPacket p) throws IOException {
		try {
			buffer.put(p);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void close() {
		stop = true;
		t.interrupt();
		super.close();
	}

	private class Sender implements Runnable {

		private BoundedBuffer<DatagramPacket> buffer;

		public Sender(BoundedBuffer<DatagramPacket> buffer) {
			this.buffer = buffer;
		}

		public void run() {
			try {
				while (true) {
					DatagramPacket p = buffer.get();
					Thread.sleep((long) (bandwidthSource.timeToSend(p.getLength())));
					DelayedDatagramSocket.super.send(p);
					if (Thread.interrupted()) {
						throw new InterruptedException();
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				if (stop) {
					return;
				} else {
					e.printStackTrace();
				}
			}
		}

	}

}
